package JasPerl::JSTL::Core::SetTag;

use 5.010;
use strict;
use warnings;

use parent qw(JasPerl::TagExt::JspBodyTag);

use JasPerl::JSTL::Core::Exceptions;
use JasPerl::PageContext;

use Scalar::Util qw(blessed);

sub set_scope {
    $_[0]->{scope} = JasPerl::PageContext->get_scope_by_name($_[1]);
}

sub set_value {
    $_[0]->{value} = $_[1];
}

sub set_var {
    $_[0]->{var} = $_[1];
}

sub set_property {
    $_[0]->{property} = $_[1];
}

sub set_target {
    $_[0]->{target} = $_[1];
}

sub get_value {
    if (exists $_[0]->{value}) {
        return $_[0]->{value};
    } else {
        return $_[0]->get_body_content();
    }
}

sub do_var {
    my ($self, $value) = @_;
    my $context = $self->get_jsp_context();

    if (defined $value) {
        $context->set_attribute($self->{var}, $value, $self->{scope});
    } else {
        $context->remove_attribute($self->{var}, $self->{scope});
    }
}

sub do_map {
    my ($self, $value) = @_;

    if (defined $value) {
        $self->{target}->{$self->{property}} = $value;
    } else {
        delete $self->{target}->{$self->{property}};
    }
}

sub do_bean {
    my ($self, $value) = @_;

    my $setter = 'set_' . $self->{property};
    $setter =~ s/(\W|_)+/_/g;
    $setter =~ s/([[:lower:]])([[:upper:]]+)/$1_\L$2\E/g;

    if (my $method = $self->{target}->can($setter)) {
        $self->{target}->$method($value);
    } else {
        JasPerl::JspTagException->throw("No setter for property '$self->{property}'");
    }
}

sub do_tag {
    my $self = shift;

    if (exists $self->{var}) {
        $self->do_var($self->get_value());
    } elsif (not defined $self->{target}) {
        JasPerl::JSTL::Core::NullAttributeException->throw('set', 'target');
    } elsif (not defined $self->{property}) {
        JasPerl::JSTL::Core::NullAttributeException->throw('set', 'property');
    } elsif (blessed $self->{target}) {
        $self->do_bean($self->get_value());
    } elsif (ref($self->{target}) eq 'HASH') {
        $self->do_map($self->get_value());
    } else {
        JasPerl::JSTL::Core::IllegalAttributeTypeException->throw(
            'set', 'target', ref $self->{target}
        );
    }
}

1;
